﻿Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.ComponentModel.Compiler
    Friend NotInheritable Class MethodBindValidator
        Inherits Validator
        ' Methods
        Public Overrides Function Validate(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            Dim errors As ValidationErrorCollection = MyBase.Validate(manager, obj)
            Dim bind As MethodBind = [TryCast](obj,MethodBind)
            If (bind Is Nothing) Then
                Throw New ArgumentException(SR.GetString("Error_UnexpectedArgumentType", New Object() { GetType(MethodBind).FullName }), "obj")
            End If
            Dim validationContext As PropertyValidationContext = [TryCast](manager.Context.Item(GetType(PropertyValidationContext)),PropertyValidationContext)
            If (validationContext Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_ContextStackItemMissing", New Object() { GetType(BindValidationContext).Name }))
            End If
            Dim activity As Activity = [TryCast](manager.Context.Item(GetType(Activity)),Activity)
            If (activity Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_ContextStackItemMissing", New Object() { GetType(Activity).Name }))
            End If
            Dim item As ValidationError = Nothing
            If String.IsNullOrEmpty(bind.Name) Then
                item = New ValidationError(SR.GetString("Error_PropertyNotSet", New Object() { "Name" }), &H116) { _
                    .PropertyName = (MyBase.GetFullPropertyName(manager) & ".Name") _
                }
            Else
                Dim context2 As BindValidationContext = [TryCast](manager.Context.Item(GetType(BindValidationContext)),BindValidationContext)
                If (context2 Is Nothing) Then
                    Dim baseType As Type = BindHelpers.GetBaseType(manager, validationContext)
                    If (Not baseType Is Nothing) Then
                        Dim accessType As AccessTypes = BindHelpers.GetAccessType(manager, validationContext)
                        context2 = New BindValidationContext(baseType, accessType)
                    End If
                End If
                If (Not context2 Is Nothing) Then
                    Dim targetType As Type = context2.TargetType
                    If (item Is Nothing) Then
                        errors.AddRange(Me.ValidateMethod(manager, activity, bind, New BindValidationContext(targetType, context2.Access)))
                    End If
                End If
            End If
            If (Not item Is Nothing) Then
                errors.Add(item)
            End If
            Return errors
        End Function

        Private Function ValidateMethod(ByVal manager As ValidationManager, ByVal activity As Activity, ByVal bind As MethodBind, ByVal validationBindContext As BindValidationContext) As ValidationErrorCollection
            Dim errors As New ValidationErrorCollection
            If ((validationBindContext.Access And AccessTypes.Write) <> 0) Then
                Dim item As New ValidationError(SR.GetString("Error_HandlerReadOnly"), &H133) { _
                    .PropertyName = MyBase.GetFullPropertyName(manager) _
                }
                errors.Add(item)
                Return errors
            End If
            If Not TypeProvider.IsAssignable(GetType(Delegate), validationBindContext.TargetType) Then
                Dim error2 As New ValidationError(SR.GetString("Error_TypeNotDelegate", New Object() { validationBindContext.TargetType.FullName }), &H134) { _
                    .PropertyName = MyBase.GetFullPropertyName(manager) _
                }
                errors.Add(error2)
                Return errors
            End If
            Dim name As String = bind.Name
            Dim enclosingActivity As Activity = Helpers.GetEnclosingActivity(activity)
            If ((name.IndexOf("."c) <> -1) AndAlso (Not enclosingActivity Is Nothing)) Then
                enclosingActivity = Helpers.GetDataSourceActivity(activity, bind.Name, name)
            End If
            If (enclosingActivity Is Nothing) Then
                Dim error3 As New ValidationError(SR.GetString("Error_NoEnclosingContext", New Object() { activity.Name }), &H130) { _
                    .PropertyName = (MyBase.GetFullPropertyName(manager) & ".Name") _
                }
                errors.Add(error3)
                Return errors
            End If
            Dim errorText As String = String.Empty
            Dim errorNumber As Integer = -1
            Dim dataSourceClass As Type = Helpers.GetDataSourceClass(enclosingActivity, manager)
            If (dataSourceClass Is Nothing) Then
                errorText = SR.GetString("Error_TypeNotResolvedInMethodName", New Object() { (MyBase.GetFullPropertyName(manager) & ".Name") })
                errorNumber = &H135
            Else
                Try 
                    ValidationHelpers.ValidateIdentifier(manager, name)
                Catch exception As Exception
                    errors.Add(New ValidationError(exception.Message, &H119))
                End Try
                Dim method As MethodInfo = validationBindContext.TargetType.GetMethod("Invoke")
                If (method Is Nothing) Then
                    Throw New Exception(SR.GetString("Error_DelegateNoInvoke", New Object() { validationBindContext.TargetType.FullName }))
                End If
                Dim list As New List([Of] Type)
                Dim info2 As ParameterInfo
                For Each info2 In method.GetParameters
                    list.Add(info2.ParameterType)
                Next
                Dim info3 As MethodInfo = Helpers.GetMethodExactMatch(dataSourceClass, name, (BindingFlags.FlattenHierarchy Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance))), Nothing, list.ToArray, Nothing)
                If (info3 Is Nothing) Then
                    If (Not dataSourceClass.GetMethod(name, (BindingFlags.FlattenHierarchy Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))) Is Nothing) Then
                        errorText = SR.GetString("Error_MethodSignatureMismatch", New Object() { (MyBase.GetFullPropertyName(manager) & ".Name") })
                        errorNumber = 310
                    Else
                        errorText = SR.GetString("Error_MethodNotExists", New Object() { (MyBase.GetFullPropertyName(manager) & ".Name"), bind.Name })
                        errorNumber = &H137
                    End If
                ElseIf Not method.ReturnType.Equals(info3.ReturnType) Then
                    errorText = SR.GetString("Error_MethodReturnTypeMismatch", New Object() { MyBase.GetFullPropertyName(manager), method.ReturnType.FullName })
                    errorNumber = &H139
                End If
            End If
            If (errorText.Length > 0) Then
                Dim error4 As New ValidationError(errorText, errorNumber) { _
                    .PropertyName = (MyBase.GetFullPropertyName(manager) & ".Path") _
                }
                errors.Add(error4)
            End If
            Return errors
        End Function

    End Class
End Namespace

